package com.xiyuan.smartutils.template.engine;

import com.xiyuan.smartutils.Classes;
import com.xiyuan.smartutils.Validates;
import com.xiyuan.smartutils.constants.HttpConstants;

import java.io.IOException;
import java.util.*;

// import com.xiyuan.http.HttpContext;
// import com.xiyuan.http.HttpRequest;
// import com.xiyuan.http.HttpSession;

/**
 * 页面变量表,<br>
 * 1.variableStack 语块变量作用域栈，<#for> <#if> <#elseif> <#else> 等语块变量表<br>
 * 2.page 当前变量<br>
 * 3.paramMap 初始化的变量表，例如解析时，传递map参数表<br>
 * 4.scopes 自定义作用域<br>
 * 5.objMap 内置对象<br>
 * 注：取值顺序为 1-7  其中 scopes 顺序取决于 @link {@link ParamScope#getScopeSort} 返回的值值越小 获取越优先
 *
 * @version v1.0.0 @author lgz 2020-7-29 新建与整理
 */
@SuppressWarnings("AlibabaConstantFieldShouldBeUpperCase")
public final class VariableMap implements HttpConstants {
    private static final LinkedList<Map<String, Object>> variablePool = new LinkedList<Map<String, Object>>();
    private static final HashMap<String, Class<?>> javaMap = new HashMap<String, Class<?>>();
    private static final HashMap<String, Class<?>> systemMap = new HashMap<String, Class<?>>();
    
    static {
        // java.lang.*
        List<Class<?>> javaList = new ArrayList<Class<?>>();
        javaList.add(Object.class);
        javaList.add(Boolean.class);
        javaList.add(Byte.class);
        javaList.add(Character.class);
        javaList.add(Short.class);
        javaList.add(Integer.class);
        javaList.add(Long.class);
        javaList.add(Float.class);
        javaList.add(Double.class);
        javaList.add(Number.class);
        javaList.add(String.class);
        javaList.add(StringBuffer.class);
        javaList.add(StringBuilder.class);
        javaList.add(Math.class);
        javaList.add(System.class);
        javaList.add(Thread.class);
        javaList.add(Runtime.class);
        javaList.add(Process.class);
        javaList.add(ProcessBuilder.class);
        javaList.add(Exception.class);
        javaList.add(Throwable.class);
        javaList.add(Error.class);
        javaList.add(LinkageError.class);
        
        
        
        // java.util.*
        javaList.add(ArrayList.class);
        javaList.add(ArrayDeque.class);
        javaList.add(Comparator.class);
        javaList.add(Calendar.class);
        javaList.add(Collections.class);
        javaList.add(Collection.class);
        javaList.add(LinkedList.class);
        javaList.add(Vector.class);
        javaList.add(HashMap.class);
        javaList.add(HashSet.class);
        javaList.add(Hashtable.class);
        javaList.add(LinkedHashMap.class);
        javaList.add(LinkedHashSet.class);
        javaList.add(WeakHashMap.class);
        javaList.add(TreeMap.class);
        javaList.add(TreeSet.class);
        javaList.add(Calendar.class);
        javaList.add(Date.class);
        javaList.add(Random.class);
        
        for (int i = 0; i < javaList.size(); i++) {
            Class<?> aClass = javaList.get(i);
            javaMap.put(aClass.getSimpleName(), aClass);
            
        }
    }
    
    /**
     * 获取Java预定义简称类
     */
    public static Class<?> getJavaClass(String name) {
        return javaMap.get(name);
    }
    
    /**
     * 获取Java预定义简称类
     */
    public static Class<?> getSystemClass(String name) {
        if (systemMap.isEmpty()) {
            synchronized (systemMap) {
                if (systemMap.isEmpty()) {
                    try {// 添加 系统工具类
                        List<Class<?>> ls = Classes.getClasses(Validates.class);
                        for (Class<?> claz : ls) {
                            systemMap.put(claz.getName().substring(claz.getName().lastIndexOf(".") + 1), claz);
                            systemMap.put(claz.getName(), claz);
                        }
                    }
                    catch (IOException e) {
                    }
                }
            }
        }
        return systemMap.get(name);
    }
    
    // 创建变量表
    private static Map<String, Object> getVariableMap() {// 这个方法主要是减少试试创建变量节省创建时间
        if (!variablePool.isEmpty()) {return variablePool.removeFirst();}
        
        return new HashMap<String, Object>();
    }
    
    /**
     * 释放变量表
     */
    private static void invalidate(Map<String, Object> variableMap) {
        if (variableMap == null) {return;}
        
        variableMap.clear();
        if (variablePool.size() == 1500) {
            return;// 最多缓存1500个变量表缓存池
        }
        
        synchronized (variablePool) {
            variablePool.add(variableMap);
        }
    }
    
    /**************************/
    // 相关处理信息
    /**************************/
    
    // 变量作用域栈，<#for> <#if> <#elseif> <#else> 等语块变量表
    private final LinkedList<Map<String, Object>> variable_stack = new LinkedList<Map<String, Object>>();
    
    // 页面变量表
    private Map<String, Object> page = new HashMap<>();
    // 参数表变量表
    private InternalScope paramMap;
    // 内置对象表
    private InternalScope objMap;
    // 变量作用域
    private List<InternalScope> scopes = new ArrayList<>(0);
    
    public VariableMap() {
    }
    
    public VariableMap(Map<String, Object> paramMap) {
        if (paramMap != null) {this.paramMap = new InternalScope(paramMap);}
    }
    
    /**
     * 取值顺序 paramMap > scopes > objMap
     * <p>
     * 其中 scopes 取值顺序取决于 @link {@link ParamScope#getScopeSort} 返回的值值越小 获取越优先
     *
     * @param paramMap 参数表
     * @param scopes   自定义变量表
     * @param objMap   内置对象
     */
    public VariableMap(Map<String, Object> paramMap, List<ParamScope> scopes,
                       Map<String, Object> objMap) {
        this(paramMap);
        if (objMap != null && !objMap.isEmpty()) {
            this.objMap = new InternalScope(new HashMap<String, Object>(objMap));
        }
        if (scopes != null && !scopes.isEmpty()) {
            List<ParamScope> list = new ArrayList<>(scopes);
            list.sort(Comparator.comparingInt(ParamScope::getScopeSort));
            this.scopes = new ArrayList<>(list.size());
            for (int i = 0; i < list.size(); i++) {
                this.scopes.add(new InternalScope(list.get(i)));
            }
        }
    }
    
    /**
     * 取值顺序 paramMap > scopes
     * <p>
     * 其中 scopes 取值顺序取决于 @link {@link ParamScope#getScopeSort} 返回的值值越小 获取越优先
     *
     * @param paramMap 参数表
     * @param scopes   自定义变量表
     */
    public VariableMap(Map<String, Object> paramMap, List<ParamScope> scopes) {
        this(paramMap);
        if (scopes != null && !scopes.isEmpty()) {
            List<ParamScope> list = new ArrayList<>(scopes);
            list.sort(Comparator.comparingInt(ParamScope::getScopeSort));
            this.scopes = new ArrayList<>(list.size());
            for (int i = 0; i < list.size(); i++) {
                this.scopes.add(new InternalScope(list.get(i)));
            }
        }
    }
    
    
    /**
     * 取值顺序 paramMap > objMap
     * <p>
     *
     * @param paramMap 参数表
     * @param objMap   内置对象
     */
    public VariableMap(Map<String, Object> paramMap, Map<String, Object> objMap) {
        this(paramMap);
        if (objMap != null && !objMap.isEmpty()) {
            this.objMap = new InternalScope(new HashMap<String, Object>(objMap));
        }
    }
    
    /**
     * 销毁
     */
    void destroy() {
        variable_stack.clear();
        // 这里设置null,应为paramMap 值引用
        paramMap = null;
        page = null;
        scopes = null;
        objMap = null;
    }
    
    public boolean has(String name) {
        // 1-2 从页面或者局部变量值
        Map<String, Object> map = getVariableStack(name);
        if (map != null && map.containsKey(name)) {return true;}
        
        // 3 从 参数表中获取
        if (paramMap != null && paramMap.hasParameter(name)) {return true;}
        
        // 4 从作用域中获取
        for (int i = 0; i < scopes.size(); i++) {if (scopes.get(i).hasParameter(name)) return true;}
        
        // 5 从 获取内置对象
        return objMap != null && objMap.hasParameter(name);
    }
    
    /**
     * 获取变量作用域
     */
    private Map<String, Object> getVariableStack(String key) {
        for (Map<String, Object> map : this.variable_stack) {
            if (map.containsKey(key)) {return map;}
        }
        
        return page;
    }
    
    
    /**
     * 获取变量值
     */
    public Object get(String key) {
        // 1-2 从页面或者局部变量值
        Map<String, Object> map = getVariableStack(key);
        if (map != null && map.containsKey(key)) {return map.get(key);}
        
        // 3 从 参数表中获取
        if (paramMap != null && paramMap.hasParameter(key)) {
            return paramMap.getParameter(key);
        }
        
        // 4 从作用域中获取
        for (int i = 0; i < scopes.size(); i++) {
            if (scopes.get(i).hasParameter(key)) return scopes.get(i).getParameter(key);
        }
        
        // 5 从 获取内置对象
        return objMap == null ? null : objMap.getParameter(key);
    }
    
    /**
     * 创建变量域空间,&放置栈顶
     */
    public void newVariableSpace() {
        this.variable_stack.addFirst(getVariableMap());
    }
    
    /**
     * 释放当前变量空间
     */
    public void releaseVariableSpace() {
        
        if (this.variable_stack.isEmpty()) {return;}
        
        invalidate(this.variable_stack.removeFirst());
    }
    
    /**
     * 将变量赋值
     */
    public void setValue(String key, Object value) {
        Map<String, Object> map = getVariableStack(key);
        map.put(key, value);
    }
    
    /**
     * 在栈顶变量空间保存变量值
     */
    public void putValue(String key, Object value) {
        if (this.variable_stack.isEmpty()) {this.page.put(key, value);}
        else {this.variable_stack.getLast().put(key, value);}
    }
    
    /**
     * 在栈顶变量空间保存移除值
     */
    public void removeValue(String key) {
        if (this.variable_stack.isEmpty()) {return;}
        
        this.variable_stack.getFirst().remove(key);
    }
    
    /**
     * 移除全局页面参数
     */
    public VariableMap remove(String key) {
        page.remove(key);
        return this;
    }
    
    /**
     * 添加内置对象，注意同名则会覆盖
     *
     * @param key   内置对象名
     * @param value 内置对象
     */
    public VariableMap addInnerObject(String key, Object value) {
        if (value != null) {objMap.getParamMap().put(key, value);}
        return this;
    }
    
    /**
     * 判断是否存在内置对象
     */
    public boolean hasInnerObj(String key) {
        return objMap.getParamMap().containsKey(key);
    }
    
    private static class InternalScope implements ParamScope {
        
        private Map<String, Object> paramMap;
        
        private ParamScope attrMap;
        
        public InternalScope(Map<String, Object> paramMap) {
            this.paramMap = paramMap;
        }
        
        public InternalScope(ParamScope scope) {
            this.attrMap = scope;
        }
        
        public Map<String, Object> getParamMap() {
            return paramMap;
        }
        
        @Override
        public int getScopeSort() {
            return attrMap == null ? Integer.MIN_VALUE : attrMap.getScopeSort();
        }
        
        @Override
        public Object getParameter(String key) {
            if (paramMap != null) return paramMap.get(key);
            return attrMap == null ? null : attrMap.getParameter(key);
        }
        
        @Override
        public boolean hasParameter(String key) {
            if (paramMap != null) return paramMap.containsKey(key);
            return attrMap != null && attrMap.hasParameter(key);
        }
    }
}
